﻿using Common;
using Common.FrontEnd;
using FrontEnd;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Util;

namespace Linguist.Acoustic.Tiedstate
{
    /// <summary>
    /// Represents a single state in an HMM
    /// </summary>
    class SenoneHMMState : IHMMState
    {
        private SenoneHMM hmm;
        private int state;
        HMMStateArc[] arcs;
        private Boolean _isEmitting;
        private ISenone senone;
        private int _hashCode;

        private static int objectCount;


        /**
        /// Constructs a SenoneHMMState
         *
        /// @param hmm   the HMM for this state
        /// @param which the index for this particular state
         */
        public SenoneHMMState(SenoneHMM hmm, int which) 
        {
            this.hmm = hmm;
            this.state = which;
            this._isEmitting = ((hmm.getTransitionMatrix().Length - 1) != state);
            if (_isEmitting) 
            {
                SenoneSequence ss = hmm.getSenoneSequence();
                senone = ss.getSenones()[state];
            }
            Utilities.objectTracker("HMMState", objectCount++);
            _hashCode = hmm.hashCode() + 37* state;
        }


        /**
        /// Gets the HMM associated with this state
         *
        /// @return the HMM
         */
        public IHMM getHMM() 
        {
    	    return hmm;
        }


        /**
        /// Gets the state
         *
        /// @return the state
         */
        public int getState() 
        {
            return state;
        }


        /**
        /// Gets the score for this HMM state
         *
        /// @param feature the feature to be scored
        /// @return the acoustic score for this state.
         */
        public float getScore(IData feature) 
        {
            return senone.getScore(feature);
        }


        /**
        /// Gets the scores for each mixture component in this HMM state
         *
        /// @param feature the feature to be scored
        /// @return the acoustic scores for the components of this state.
         */
        public float[] calculateComponentScore(IData feature) 
        {
            hmm.getSenoneSequence();
            return senone.calculateComponentScore(feature);
        }


        /**
        /// Gets the senone for this HMM state
         *
        /// @return the senone for this state.
         */
        public ISenone getSenone() 
        {
            return senone;
        }


        /**
        /// Determines if two HMMStates are equal
         *
        /// @param other the state to compare this one to
        /// @return true if the states are equal
         */
        override
        public Boolean Equals(Object other) 
        {
            if (this == other) {
                return true;
            } 
            else if (!(other is SenoneHMMState)) 
            {
                return false;
            } else {
                SenoneHMMState otherState = (SenoneHMMState) other;
                return this.hmm == otherState.hmm &&
                        this.state == otherState.state;
            }
        }


        /**
        /// Returns the hashcode for this state
         *
        /// @return the hashcode
         */
        public int hashCode() 
        {
            return _hashCode;
        }


        /**
        /// Determines if this HMMState is an emitting state
         *
        /// @return true if the state is an emitting state
         */
        // TODO: We may have non-emitting entry states as well.
        public Boolean isEmitting() 
        {
            return _isEmitting;
        }


        /**
        /// Retrieves the state of successor states for this state
         *
        /// @return the set of successor state arcs
         */
        public IHMMStateArc[] getSuccessors() 
        {
            if (arcs == null) {
                List<HMMStateArc> list = new List<HMMStateArc>();
                float[][] transitionMatrix = hmm.getTransitionMatrix();

                for (int i = 0; i < transitionMatrix.Length; i++) 
                {
                    if (transitionMatrix[state][i] > LogMath.LOG_ZERO) 
                    {
                        HMMStateArc arc = new HMMStateArc(hmm.getState(i),
                                transitionMatrix[state][i]);
                        list.Add(arc);
                    }
                }
                arcs = list.ToArray();
            }
            return arcs;
        }


        /**
        /// Determines if this state is an exit state of the HMM
         *
        /// @return true if the state is an exit state
         */
        public Boolean isExitState() 
        {
            // return (hmm.getTransitionMatrix().length - 1) == state;
            return !_isEmitting;
        }


        /**
        /// returns a string representation of this object
         *
        /// @return a string representation
         */
        override
        public String ToString() 
        {
            return "HMMS " + hmm + " state " + state;
        }

	    public IMixtureComponent[] getMixtureComponents() {
		    return senone.getMixtureComponents();
	    }

	    public long getMixtureId() {
		    return senone.getID();
	    }

	    public float[] getLogMixtureWeights() {
		    return senone.getLogMixtureWeights();
	    }
    }
}
